#ifndef _IMI_JPEG_H_
#define _IMI_JPEG_H_
//#include <wtypes.h>
#include <malloc.h>
#include <math.h>

#define DCTSIZE 8
#define DCTBLOCKSIZE 64
#define DC_MAX_QUANTED 2047 //������DC�����ֵ
#define DC_MIN_QUANTED -2048 //������DC����Сֵ

//Huffman��ṹ
typedef struct tagHUFFCODE
{
	unsigned short code; // huffman ����
	unsigned char length; // ���볤��
	unsigned short val; // ���ֶ�Ӧ��ֵ
}HUFFCODE;

typedef struct tagJPEGINFO
{
	// ���2��FDCT�任Ҫ���ʽ��������
	float YQT_DCT[DCTBLOCKSIZE];
	float UVQT_DCT[DCTBLOCKSIZE];
	// ���2��������
	unsigned char YQT[DCTBLOCKSIZE];
	unsigned char UVQT[DCTBLOCKSIZE];

	// ���VLI��
	unsigned char VLI_TAB[4096];
	unsigned char* pVLITAB; //VLI_TAB�ı���,ʹ�±���-2048-2048
	//���4��Huffman��
	HUFFCODE STD_DC_Y_HT[12];
	HUFFCODE STD_DC_UV_HT[12];
	HUFFCODE STD_AC_Y_HT[256];
	HUFFCODE STD_AC_UV_HT[256];
	unsigned char bytenew; // The byte that will be written in the JPG file
	char bytepos; //bit position in the byte we write (bytenew)
}JPEGINFO;

//�ļ���ʼ,��ʼ���Ϊ0xFFD8
const static unsigned short SOITAG = 0xD8FF;

//�ļ�����,�������Ϊ0xFFD9
const static unsigned short EOITAG = 0xD9FF;

//���� 8x8 Z�任��
const static unsigned char FZBT[64] =
{
	0, 1, 5, 6, 14,15,27,28,
	2, 4, 7, 13,16,26,29,42,
	3, 8, 12,17,25,30,41,43,
	9, 11,18,24,31,40,44,53,
	10,19,23,32,39,45,52,54,
	20,22,33,38,46,51,55,60,
	21,34,37,47,50,56,59,61,
	35,36,48,49,57,58,62,63
};

//��׼�����ź�����ģ��
const static unsigned char std_Y_QT[64] =
{
	16, 11, 10, 16, 24, 40, 51, 61,
	12, 12, 14, 19, 26, 58, 60, 55,
	14, 13, 16, 24, 40, 57, 69, 56,
	14, 17, 22, 29, 51, 87, 80, 62,
	18, 22, 37, 56, 68, 109,103,77,
	24, 35, 55, 64, 81, 104,113,92,
	49, 64, 78, 87, 103,121,120,101,
	72, 92, 95, 98, 112,100,103,99
};

//��׼ɫ���ź�����ģ��
const static unsigned char std_UV_QT[64] =
{
	17, 18, 24, 47, 99, 99, 99, 99,
	18, 21, 26, 66, 99, 99, 99, 99,
	24, 26, 56, 99, 99, 99, 99, 99,
	47, 66, 99 ,99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99
};

static const double aanScaleFactor[8] = {1.0, 1.387039845, 1.306562965, 1.175875602,1.0, 0.785694958, 0.541196100, 0.275899379};
// ��׼Huffman�� (cf. JPEG standard section K.3)
static unsigned char STD_DC_Y_NRCODES[17]={0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static unsigned char STD_DC_Y_VALUES[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static unsigned char STD_DC_UV_NRCODES[17]={0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
static unsigned char STD_DC_UV_VALUES[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

static unsigned char STD_AC_Y_NRCODES[17]={0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0X7D };
static unsigned char STD_AC_Y_VALUES[162]= {
	0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
	0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
	0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
	0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
	0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
	0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
	0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
	0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
	0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
	0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
	0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
	0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
	0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
	0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
	0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
	0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
	0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
	0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
	0xf9, 0xfa };

static unsigned char STD_AC_UV_NRCODES[17]={0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0X77};
static unsigned char STD_AC_UV_VALUES[162]={
	0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
	0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
	0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
	0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
	0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
	0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
	0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
	0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
	0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
	0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
	0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
	0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
	0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
	0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
	0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
	0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
	0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
	0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
	0xf9, 0xfa };

static unsigned short mask[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

		//JFIF APP0�νṹ
#pragma pack(push,1)
typedef struct tagJPEGAPP0
{
	unsigned short segmentTag; //APP0�α�ǣ�����ΪFFE0
	unsigned short length; //�γ��ȣ�һ��Ϊ16�����û������ͼ
	char id[5]; //�ļ���� "JFIF" + "\0"
	unsigned short ver; //�ļ��汾��һ��Ϊ0101��0102
	unsigned char densityUnit; //�ܶȵ�λ��0=�޵�λ 1=����/Ӣ�� 2=����/����
	unsigned short densityX; //X�᷽���ܶ�,ͨ��д1
	unsigned short densityY; //Y�᷽���ܶ�,ͨ��д1
	unsigned char thp; //����ͼˮƽ������,д0
	unsigned char tvp; //����ͼ��ֱ������,д0
}JPEGAPP0;// = {0xE0FF,16,'J','F','I','F',0,0x0101,0,1,1,0,0};
#pragma pack(pop)

		//JFIF DQT�νṹ(8 bits ������)
#pragma pack(push,1)
typedef struct tagJPEGDQT_8BITS
{
	unsigned short segmentTag; //DQT�α�ǣ�����Ϊ0xFFDB
	unsigned short length; //�γ���,������0x4300
	unsigned char tableInfo; //��������Ϣ
	unsigned char table[64]; //������(8 bits)
}JPEGDQT_8BITS;
#pragma pack(pop)

		//JFIF SOF0�νṹ(���)�����໹��SOF1-SOFF
#pragma pack(push,1)
typedef struct tagJPEGSOF0_24BITS
{
	unsigned short segmentTag; //SOF�α�ǣ�����Ϊ0xFFC0
	unsigned short length; //�γ��ȣ����ͼΪ17���Ҷ�ͼΪ11
	unsigned char precision; //���ȣ�ÿ���źŷ������õ�λ��������ϵͳΪ0x08
	unsigned short height; //ͼ��߶�
	unsigned short width; //ͼ����
	unsigned char sigNum; //�ź����������JPEGӦ��Ϊ3���Ҷ�Ϊ1
	unsigned char YID; //�źű�ţ�����Y
	unsigned char HVY; //������ʽ��0-3λ�Ǵ�ֱ������4-7λ��ˮƽ����
	unsigned char QTY; //��Ӧ�������
	unsigned char UID; //�źű�ţ�ɫ��U
	unsigned char HVU; //������ʽ��0-3λ�Ǵ�ֱ������4-7λ��ˮƽ����
	unsigned char QTU; //��Ӧ�������
	unsigned char VID; //�źű�ţ�ɫ��V
	unsigned char HVV; //������ʽ��0-3λ�Ǵ�ֱ������4-7λ��ˮƽ����
	unsigned char QTV; //��Ӧ�������
}JPEGSOF0_24BITS;// = {0xC0FF,0x0011,8,0,0,3,1,0x11,0,2,0x11,1,3,0x11,1};
#pragma pack(pop)

		//JFIF DHT�νṹ
#pragma pack(push,1)
typedef struct tagJPEGDHT
{
	unsigned short segmentTag; //DHT�α�ǣ�����Ϊ0xFFC4
	unsigned short length; //�γ���
	unsigned char tableInfo; //����Ϣ������ϵͳ�� bit0-3 ΪHuffman���������bit4 Ϊ0ָDC��Huffman�� Ϊ1ָAC��Huffman��bit5-7����������Ϊ0
	unsigned char huffCode[16];//1-16λ��Huffman���ֵ��������ֱ���������[1-16]��
	//unsigned char* huffVal; //���δ�Ÿ����ֶ�Ӧ��ֵ
}JPEGDHT;
#pragma pack(pop)

		// JFIF SOS�νṹ����ʣ�
#pragma pack(push,1)
typedef struct tagJPEGSOS_24BITS
{
	unsigned short segmentTag; //SOS�α�ǣ�����Ϊ0xFFDA
	unsigned short length; //�γ��ȣ�������12
	unsigned char sigNum; //�źŷ����������ͼΪ0x03,�Ҷ�ͼΪ0x01
	unsigned char YID; //����Y�ź�ID,������1
	unsigned char HTY; //Huffman��ţ�bit0-3ΪDC�źŵı�bit4-7ΪAC�źŵı�
	unsigned char UID; //����Y�ź�ID,������2
	unsigned char HTU;
	unsigned char VID; //����Y�ź�ID,������3
	unsigned char HTV;
	unsigned char Ss; //����ϵͳ��Ϊ0
	unsigned char Se; //����ϵͳ��Ϊ63
	unsigned char Bf; //����ϵͳ��Ϊ0
}JPEGSOS_24BITS;// = {0xDAFF,0x000C,3,1,0,2,0x11,3,0x11,0,0x3F,0};
#pragma pack(pop)

		//AC�ź��м���Žṹ
typedef struct tagACSYM
{
	unsigned char zeroLen; //0�г�
	unsigned char codeLen; //���ȱ��볤��
	short amplitude;//���
}ACSYM;

//DC/AC �м����2�����ṹ
typedef struct tagSYM2
{
	short amplitude;//���
	unsigned char codeLen; //�������(��������ʽ��������ݵ�λ��)
}SYM2;

typedef struct tagBMBUFINFO
{
	unsigned int imgWidth;
	unsigned int imgHeight;
	unsigned int buffWidth;
	unsigned int buffHeight;
	unsigned short BitCount;
	unsigned char padSize;
}BMBUFINFO;

/*��YUV 420 ת����YUV444 UV�岹*/
void ProcessUV(unsigned char* pUVBuf,unsigned char* pTmpUVBuf,int width,int height,int nStride)
{
	int nTmpUV = (height * nStride) >> 2;
	int i,j;
	for(j = 0 ; j < height ; j++)
	{
		for(i = 0 ; i < width ; i++)
		{
			pUVBuf[j* nStride + i] = *(pTmpUVBuf + (j >> 1) * (nStride >> 1) + (i >> 1));
		}
	}
}

int QualityScaling(int quality)
	/* Convert a user-specified quality rating to a percentage scaling factor
	* for an underlying quantization table, using our recommended scaling curve.
	* The input 'quality' factor should be 0 (terrible) to 100 (very good).
	*/
{
	/* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */
	if (quality <= 0) quality = 1;
	if (quality > 100) quality = 100;

	/* The basic table is used as-is (scaling 100) for a quality of 50.
	* Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
	* note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
	* to make all the table entries 1 (hence, minimum quantization loss).
	* Qualities 1..50 are converted to scaling percentage 5000/Q.
	*/
	if (quality < 50)
		quality = 5000 / quality;
	else
		quality = 200 - quality*2;

	return quality;
}

void DivBuff(unsigned char* pBuf,int width,int height,int nStride,int xLen,int yLen)
{
	int xBufs = width / xLen; //X�᷽�����и�����
	int yBufs = height / yLen; //Y�᷽�����и�����
	int tmpBufLen = xBufs * xLen * yLen; //������ʱ����������
	unsigned char* tmpBuf = (unsigned char *)malloc(tmpBufLen); //������ʱ����
	int i; //��ʱ����
	int j;
	int k;
	int n;
	int bufOffset = 0; //�иʼ��ƫ����

	for (i = 0; i < yBufs; ++i) //ѭ��Y�����и�����
	{
		n = 0; //��λ��ʱ������ƫ����
		for (j = 0; j < xBufs; ++j) //ѭ��X�����и�����
		{
			bufOffset = yLen * i * nStride + j * xLen; //���㵥Ԫ�źſ������ƫ����
			for (k = 0; k < yLen; ++k) //ѭ���������
			{
				memcpy(tmpBuf + n,pBuf +bufOffset,xLen); //����һ�е���ʱ����
				n += xLen; //������ʱ������ƫ����
				bufOffset += nStride; //�������뻺����ƫ����
			}
		}
		memcpy(pBuf +i * tmpBufLen,tmpBuf,tmpBufLen); //������ʱ�������ݵ����뻺��
	}
	free(tmpBuf); //ɾ����ʱ����
}

void SetQuantTable(const unsigned char* std_QT,unsigned char* QT, int Q)
{
	int tmpVal = 0;
	int i;
	for (i = 0; i < DCTBLOCKSIZE; ++i)
	{
		tmpVal = (std_QT[i] * Q + 50L) / 100L;

		if (tmpVal < 1) //��ֵ��Χ�޶�
		{
			tmpVal = 1L;
		}
		if (tmpVal > 255)
		{
			tmpVal = 255L;
		}
		QT[FZBT[i]] = (unsigned char)tmpVal;
	}
}

//Ϊfloat AA&N IDCT�㷨��ʼ��������
void InitQTForAANDCT(JPEGINFO *pJpgInfo)
{
	unsigned int i = 0; //��ʱ����
	unsigned int j = 0;
	unsigned int k = 0;

	for (i = 0; i < DCTSIZE; i++) //��ʼ�������ź�������
	{
		for (j = 0; j < DCTSIZE; j++)
		{
			pJpgInfo->YQT_DCT[k] = (float) (1.0 / ((double) pJpgInfo->YQT[FZBT[k]] *
				aanScaleFactor[i] * aanScaleFactor[j] * 8.0));
			++k;
		}
	}

	k = 0;
	for (i = 0; i < DCTSIZE; i++) //��ʼ��ɫ���ź�������
	{
		for (j = 0; j < DCTSIZE; j++)
		{
			pJpgInfo->UVQT_DCT[k] = (float) (1.0 / ((double) pJpgInfo->UVQT[FZBT[k]] *
				aanScaleFactor[i] * aanScaleFactor[j] * 8.0));
			++k;
		}
	}
}

//���ط��ŵĳ���
unsigned char ComputeVLI(short val)
{
	unsigned char binStrLen = 0;
	val = abs(val);
	//��ȡ�������볤��
	if(val == 1)
	{
		binStrLen = 1;
	}
	else if(val >= 2 && val <= 3)
	{
		binStrLen = 2;
	}
	else if(val >= 4 && val <= 7)
	{
		binStrLen = 3;
	}
	else if(val >= 8 && val <= 15)
	{
		binStrLen = 4;
	}
	else if(val >= 16 && val <= 31)
	{
		binStrLen = 5;
	}
	else if(val >= 32 && val <= 63)
	{
		binStrLen = 6;
	}
	else if(val >= 64 && val <= 127)
	{
		binStrLen = 7;
	}
	else if(val >= 128 && val <= 255)
	{
		binStrLen = 8;
	}
	else if(val >= 256 && val <= 511)
	{
		binStrLen = 9;
	}
	else if(val >= 512 && val <= 1023)
	{
		binStrLen = 10;
	}
	else if(val >= 1024 && val <= 2047)
	{
		binStrLen = 11;
	}

	return binStrLen;
}

//********************************************************************
// ��������:BuildVLITable
//
// ����˵��:����VLI��
//
// ����˵��:
//********************************************************************
void BuildVLITable(JPEGINFO *pJpgInfo)
{
	short i = 0;

	for (i = 0; i < DC_MAX_QUANTED; ++i)
	{
		pJpgInfo->pVLITAB[i] = ComputeVLI(i);
	}

	for (i = DC_MIN_QUANTED; i < 0; ++i)
	{
		pJpgInfo->pVLITAB[i] = ComputeVLI(i);
	}
}

//д�ļ���ʼ���
int WriteSOI(unsigned char* pOut,int nDataLen)
{
	memcpy(pOut+nDataLen,&SOITAG,sizeof(SOITAG));
	return nDataLen+sizeof(SOITAG);
}

//д���ļ��������
int WriteEOI(unsigned char* pOut,int nDataLen)
{
	memcpy(pOut+nDataLen,&EOITAG,sizeof(EOITAG));
	return nDataLen + sizeof(EOITAG);
}

//дAPP0��
int WriteAPP0(unsigned char* pOut,int nDataLen)
{
	JPEGAPP0 APP0;
	APP0.segmentTag = 0xE0FF;
	APP0.length = 0x1000;
	APP0.id[0] = 'J';
	APP0.id[1] = 'F';
	APP0.id[2] = 'I';
	APP0.id[3] = 'F';
	APP0.id[4] = 0;
	APP0.ver = 0x0101;
	APP0.densityUnit = 0x00;
	APP0.densityX = 0x0100;
	APP0.densityY = 0x0100;
	APP0.thp = 0x00;
	APP0.tvp = 0x00;
	memcpy(pOut+nDataLen,&APP0,sizeof(APP0));
	return nDataLen + sizeof(APP0);
}

//д��DQT��
int WriteDQT(JPEGINFO *pJpgInfo,unsigned char* pOut,int nDataLen)
{
	unsigned int i = 0;
	JPEGDQT_8BITS DQT_Y;
	DQT_Y.segmentTag = 0xDBFF;
	DQT_Y.length = 0x4300;
	DQT_Y.tableInfo = 0x00;
	for (i = 0; i < DCTBLOCKSIZE; i++)
	{
		DQT_Y.table[i] = pJpgInfo->YQT[i];
	}
	memcpy(pOut+nDataLen , &DQT_Y,sizeof(DQT_Y));
	nDataLen += sizeof(DQT_Y);
	DQT_Y.tableInfo = 0x01;
	for (i = 0; i < DCTBLOCKSIZE; i++)
	{
		DQT_Y.table[i] = pJpgInfo->UVQT[i];
	}
	memcpy(pOut+nDataLen,&DQT_Y,sizeof(DQT_Y));
	nDataLen += sizeof(DQT_Y);
	return nDataLen;
}


// ����8λ�͵�8λ����
unsigned short Intel2Moto(unsigned short val)
{
	unsigned char highBits = (unsigned char)(val / 256);
	unsigned char lowBits = (unsigned char)(val % 256);

	return lowBits * 256 + highBits;
}

//д��SOF��
int WriteSOF(unsigned char* pOut,int nDataLen,int width,int height)
{
	JPEGSOF0_24BITS SOF;
	SOF.segmentTag = 0xC0FF;
	SOF.length = 0x1100;
	SOF.precision = 0x08;
	SOF.height = Intel2Moto((unsigned short)height);
	SOF.width = Intel2Moto((unsigned short)width);
	SOF.sigNum = 0x03;
	SOF.YID = 0x01;
	SOF.QTY = 0x00;
	SOF.UID = 0x02;
	SOF.QTU = 0x01;
	SOF.VID = 0x03;
	SOF.QTV = 0x01;
	SOF.HVU = 0x11;
	SOF.HVV = 0x11;
	/*switch (this->SamplingType)
	{
	case 1:
	SOF.HVY = 0x11;
	break;

	case 2:
	SOF.HVY = 0x12;
	break;

	case 3:
	SOF.HVY = 0x21;
	break;

	case 4:
	SOF.HVY = 0x22;
	break;
	}*/
	SOF.HVY = 0x11;
	memcpy(pOut + nDataLen,&SOF,sizeof(SOF));
	return nDataLen + sizeof(SOF);
}

//д1�ֽڵ��ļ�
int WriteByte(unsigned char val,unsigned char* pOut,int nDataLen)
{
	pOut[nDataLen] = val;
	return nDataLen + 1;
}

//д��DHT��
int WriteDHT(unsigned char* pOut,int nDataLen)
{
	unsigned int i = 0;

	JPEGDHT DHT;
	DHT.segmentTag = 0xC4FF;
	DHT.length = Intel2Moto(19 + 12);
	DHT.tableInfo = 0x00;
	for (i = 0; i < 16; i++)
	{
		DHT.huffCode[i] = STD_DC_Y_NRCODES[i + 1];
	}
	memcpy(pOut+nDataLen,&DHT,sizeof(DHT));
	nDataLen += sizeof(DHT);
	for (i = 0; i <= 11; i++)
	{
		nDataLen = WriteByte(STD_DC_Y_VALUES[i],pOut,nDataLen);
	}
	//------------------------------------------------
	DHT.tableInfo = 0x01;
	for (i = 0; i < 16; i++)
	{
		DHT.huffCode[i] = STD_DC_UV_NRCODES[i + 1];
	}
	memcpy(pOut+nDataLen,&DHT,sizeof(DHT));
	nDataLen += sizeof(DHT);
	for (i = 0; i <= 11; i++)
	{
		nDataLen = WriteByte(STD_DC_UV_VALUES[i],pOut,nDataLen);
	}
	//----------------------------------------------------
	DHT.length = Intel2Moto(19 + 162);
	DHT.tableInfo = 0x10;
	for (i = 0; i < 16; i++)
	{
		DHT.huffCode[i] = STD_AC_Y_NRCODES[i + 1];
	}
	memcpy(pOut+nDataLen,&DHT,sizeof(DHT));
	nDataLen += sizeof(DHT);
	for (i = 0; i <= 161; i++)
	{
		nDataLen = WriteByte(STD_AC_Y_VALUES[i],pOut,nDataLen);
	}
	//-----------------------------------------------------
	DHT.tableInfo = 0x11;
	for (i = 0; i < 16; i++)
	{
		DHT.huffCode[i] = STD_AC_UV_NRCODES[i + 1];
	}
	memcpy(pOut + nDataLen,&DHT,sizeof(DHT));
	nDataLen += sizeof(DHT);
	for (i = 0; i <= 161; i++)
	{
		nDataLen = WriteByte(STD_AC_UV_VALUES[i],pOut,nDataLen);
	}
	return nDataLen;
}

//д��SOS��
int WriteSOS(unsigned char* pOut,int nDataLen)
{
	JPEGSOS_24BITS SOS;
	SOS.segmentTag = 0xDAFF;
	SOS.length = 0x0C00;
	SOS.sigNum = 0x03;
	SOS.YID = 0x01;
	SOS.HTY = 0x00;
	SOS.UID = 0x02;
	SOS.HTU = 0x11;
	SOS.VID = 0x03;
	SOS.HTV = 0x11;
	SOS.Se = 0x3F;
	SOS.Ss = 0x00;
	SOS.Bf = 0x00;
	memcpy(pOut+nDataLen,&SOS,sizeof(SOS));
	return nDataLen+sizeof(SOS);
}

// ���ɱ�׼Huffman��
void BuildSTDHuffTab(unsigned char* nrcodes,unsigned char* stdTab,HUFFCODE* huffCode)
{
	unsigned char i = 0; //��ʱ����
	unsigned char j = 0;
	unsigned char k = 0;
	unsigned short code = 0;

	for (i = 1; i <= 16; i++)
	{
		for (j = 1; j <= nrcodes[i]; j++)
		{
			huffCode[stdTab[k]].code = code;
			huffCode[stdTab[k]].length = i;
			++k;
			++code;
		}
		code*=2;
	}

	for (i = 0; i < k; i++)
	{
		huffCode[i].val = stdTab[i];
	}
}

// 8x8�ĸ�����ɢ���ұ任
void FDCT(float* lpBuff)
{
	float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
	float tmp10, tmp11, tmp12, tmp13;
	float z1, z2, z3, z4, z5, z11, z13;
	float* dataptr;
	int ctr;

	/* ��һ���֣����н��м��� */
	dataptr = lpBuff;
	for (ctr = DCTSIZE-1; ctr >= 0; ctr--)
	{
		tmp0 = dataptr[0] + dataptr[7];
		tmp7 = dataptr[0] - dataptr[7];
		tmp1 = dataptr[1] + dataptr[6];
		tmp6 = dataptr[1] - dataptr[6];
		tmp2 = dataptr[2] + dataptr[5];
		tmp5 = dataptr[2] - dataptr[5];
		tmp3 = dataptr[3] + dataptr[4];
		tmp4 = dataptr[3] - dataptr[4];

		/* ��ż����������� */
		tmp10 = tmp0 + tmp3; /* phase 2 */
		tmp13 = tmp0 - tmp3;
		tmp11 = tmp1 + tmp2;
		tmp12 = tmp1 - tmp2;

		dataptr[0] = tmp10 + tmp11; /* phase 3 */
		dataptr[4] = tmp10 - tmp11;

		z1 = (float)((tmp12 + tmp13) * (0.707106781)); /* c4 */
		dataptr[2] = tmp13 + z1; /* phase 5 */
		dataptr[6] = tmp13 - z1;

		/* ����������м��� */
		tmp10 = tmp4 + tmp5; /* phase 2 */
		tmp11 = tmp5 + tmp6;
		tmp12 = tmp6 + tmp7;

		z5 = (float)((tmp10 - tmp12) * ( 0.382683433)); /* c6 */
		z2 = (float)((0.541196100) * tmp10 + z5); /* c2-c6 */
		z4 = (float)((1.306562965) * tmp12 + z5); /* c2+c6 */
		z3 = (float)(tmp11 * (0.707106781)); /* c4 */

		z11 = tmp7 + z3; /* phase 5 */
		z13 = tmp7 - z3;

		dataptr[5] = z13 + z2; /* phase 6 */
		dataptr[3] = z13 - z2;
		dataptr[1] = z11 + z4;
		dataptr[7] = z11 - z4;

		dataptr += DCTSIZE; /* ��ָ��ָ����һ�� */
	}

	/* �ڶ����֣����н��м��� */
	dataptr = lpBuff;
	for (ctr = DCTSIZE-1; ctr >= 0; ctr--)
	{
		tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
		tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
		tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
		tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
		tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
		tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
		tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
		tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];

		/* ��ż����������� */
		tmp10 = tmp0 + tmp3; /* phase 2 */
		tmp13 = tmp0 - tmp3;
		tmp11 = tmp1 + tmp2;
		tmp12 = tmp1 - tmp2;

		dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
		dataptr[DCTSIZE*4] = tmp10 - tmp11;

		z1 = (float)((tmp12 + tmp13) * (0.707106781)); /* c4 */
		dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
		dataptr[DCTSIZE*6] = tmp13 - z1;

		/* ����������м��� */
		tmp10 = tmp4 + tmp5; /* phase 2 */
		tmp11 = tmp5 + tmp6;
		tmp12 = tmp6 + tmp7;

		z5 = (float)((tmp10 - tmp12) * (0.382683433)); /* c6 */
		z2 = (float)((0.541196100) * tmp10 + z5); /* c2-c6 */
		z4 = (float)((1.306562965) * tmp12 + z5); /* c2+c6 */
		z3 = (float)(tmp11 * (0.707106781)); /* c4 */

		z11 = tmp7 + z3; /* phase 5 */
		z13 = tmp7 - z3;

		dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
		dataptr[DCTSIZE*3] = z13 - z2;
		dataptr[DCTSIZE*1] = z11 + z4;
		dataptr[DCTSIZE*7] = z11 - z4;

		++dataptr; /* ��ָ��ָ����һ�� */
	}
}

//********************************************************************
// ��������:WriteBitsStream
//
// ����˵��:д���������
//
// ����˵��:
// value:��Ҫд���ֵ
// codeLen:�����Ƴ���
//********************************************************************
int WriteBitsStream(JPEGINFO *pJpgInfo,unsigned short value,unsigned char codeLen,unsigned char* pOut,int nDataLen)
{
	char posval;//bit position in the bitstring we read, should be<=15 and >=0
	posval=codeLen-1;
	while (posval>=0)
	{
		if (value & mask[posval])
		{
			pJpgInfo->bytenew|=mask[pJpgInfo->bytepos];
		}
		posval--;
		pJpgInfo->bytepos--;
		if (pJpgInfo->bytepos<0)
		{
			if (pJpgInfo->bytenew==0xFF)
			{
				nDataLen = WriteByte(0xFF,pOut,nDataLen);
				nDataLen = WriteByte(0,pOut,nDataLen);
			}
			else
			{
				nDataLen = WriteByte(pJpgInfo->bytenew,pOut,nDataLen);
			}
			pJpgInfo->bytepos=7;
			pJpgInfo->bytenew=0;
		}
	}
	return nDataLen;
}

//********************************************************************
// ��������:WriteBits
//
// ����˵��:д���������
//
// ����˵��:
// value:AC/DC�źŵ����
//********************************************************************
int WriteBits(JPEGINFO *pJpgInfo,HUFFCODE huffCode,unsigned char* pOut,int nDataLen)
{
	return WriteBitsStream(pJpgInfo,huffCode.code,huffCode.length,pOut,nDataLen);
}

int WriteBits2(JPEGINFO *pJpgInfo,SYM2 sym,unsigned char* pOut,int nDataLen)
{
	return WriteBitsStream(pJpgInfo,sym.amplitude,sym.codeLen,pOut,nDataLen);
}

//********************************************************************
// ��������:BuildSym2
//
// ����˵��:���źŵ����VLI����,���ر��볤�Ⱥ��ź�����ķ���
//
// ����˵��:
// value:AC/DC�źŵ����
//********************************************************************
SYM2 BuildSym2(short value)
{
	SYM2 Symbol;

	Symbol.codeLen = ComputeVLI(value); //��ȡ���볤��
	Symbol.amplitude = 0;
	if (value >= 0)
	{
		Symbol.amplitude = value;
	}
	else
	{
		Symbol.amplitude = (short)(pow((float)2,(int)Symbol.codeLen)-1) + value; //���㷴��
	}

	return Symbol;
}

//********************************************************************
// ��������:RLEComp
//
// ����˵��:ʹ��RLE�㷨��ACѹ��,������������1,0,0,0,3,0,5
// ���Ϊ(0,1)(3,3)(1,5),��λ��ʾ��λ����ǰ0�ĸ���
// ��λ��4bits��ʾ,0�ĸ���������ʾ��Χ�����Ϊ(15,0)
// �����0��������һ�������б�ʾ.
//
// ����˵��:
// lpbuf:���뻺��,8x8�任�źŻ���
// lpOutBuf:�������,�ṹ����,�ṹ��Ϣ��ͷ�ļ�
// resultLen:������峤��,���������ŵ�����
//********************************************************************
void RLEComp(short* lpbuf,ACSYM* lpOutBuf,unsigned char *resultLen)
{
	unsigned char zeroNum = 0; //0�г̼�����
	unsigned int EOBPos = 0; //EOB����λ��
	const unsigned char MAXZEROLEN = 15; //���0�г�
	unsigned int i = 0; //��ʱ����
	unsigned int j = 0;

	EOBPos = DCTBLOCKSIZE - 1; //������ʼλ�ã������һ���źſ�ʼ
	for (i = EOBPos; i > 0; i--) //������AC�ź���0�ĸ���
	{
		if (lpbuf[i] == 0) //�ж������Ƿ�Ϊ0
		{
			--EOBPos; //��ǰһλ
		}
		else //������0������
		{
			break;
		}
	}

	for (i = 1; i <= EOBPos; i++) //�ӵڶ����źţ���AC�źſ�ʼ����
	{
		if (lpbuf[i] == 0 && zeroNum < MAXZEROLEN) //����ź�Ϊ0����������С��15
		{
			++zeroNum;
		}
		else
		{
			lpOutBuf[j].zeroLen = zeroNum; //0�г̣��������ȣ�
			lpOutBuf[j].codeLen = ComputeVLI(lpbuf[i]); //���ȱ��볤��
			lpOutBuf[j].amplitude = lpbuf[i]; //���
			zeroNum = 0; //0��������λ
			++(*resultLen); //��������++
			++j; //���ż���
		}
	}
}

// ����DU(���ݵ�Ԫ)
int ProcessDU(JPEGINFO *pJpgInfo,float* lpBuf,float* quantTab,HUFFCODE* dcHuffTab,HUFFCODE* acHuffTab,short* DC,unsigned char* pOut,int nDataLen)
{
	unsigned char i = 0; //��ʱ����
	unsigned int j = 0;
	short diffVal = 0; //DC����ֵ
	unsigned char acLen = 0; //�ر����AC�м���ŵ�����
	short sigBuf[DCTBLOCKSIZE]; //�������źŻ���
	ACSYM acSym[DCTBLOCKSIZE]; //AC�м���Ż���

	FDCT(lpBuf); //��ɢ���ұ任

	for (i = 0; i < DCTBLOCKSIZE; i++) //��������
	{
		sigBuf[FZBT[i]] = (short)((lpBuf[i] * quantTab[i] + 16384.5) - 16384);
	}
	//-----------------------------------------------------
	//��DC�źű��룬д���ļ�
	//DPCM����
	diffVal = sigBuf[0] - *DC;
	*DC = sigBuf[0];
	//����Huffman��д����Ӧ������
	if (diffVal == 0)
	{

		nDataLen = WriteBits(pJpgInfo,dcHuffTab[0],pOut,nDataLen);
	}
	else
	{
		nDataLen = WriteBits(pJpgInfo,dcHuffTab[pJpgInfo->pVLITAB[diffVal]],pOut,nDataLen);
		nDataLen = WriteBits2(pJpgInfo,BuildSym2(diffVal),pOut,nDataLen);
	}
	//-------------------------------------------------------
	//��AC�źű��벢д���ļ�
	for (i = 63; (i > 0) && (sigBuf[i] == 0); i--) //�ж�ac�ź��Ƿ�ȫΪ0
	{
		//ע�⣬��ѭ��
	}
	if (i == 0) //���ȫΪ0
	{
		nDataLen = WriteBits(pJpgInfo,acHuffTab[0x00],pOut,nDataLen); //д���������
	}
	else
	{
		RLEComp(sigBuf,&acSym[0],&acLen); //��AC���г��ȱ���
		for (j = 0; j < acLen; j++) //���ζ�AC�м����Huffman����
		{
			if (acSym[j].codeLen == 0) //�Ƿ�������16��0
			{
				nDataLen = WriteBits(pJpgInfo,acHuffTab[0xF0],pOut,nDataLen); //д��(15,0)
			}
			else
			{
				nDataLen = WriteBits(pJpgInfo,acHuffTab[acSym[j].zeroLen * 16 + acSym[j].codeLen],pOut,nDataLen); //
				nDataLen = WriteBits2(pJpgInfo,BuildSym2(acSym[j].amplitude),pOut,nDataLen);
			}
		}
		if (i != 63) //������λ��0������д��EOB
		{
			nDataLen = WriteBits(pJpgInfo,acHuffTab[0x00],pOut,nDataLen);
		}
	}
	return nDataLen;
}

//********************************************************************
// ��������:ProcessData
//
// ����˵��:����ͼ������FDCT-QUANT-HUFFMAN
//
// ����˵��:
// lpYBuf:����Y�ź����뻺��
// lpUBuf:ɫ��U�ź����뻺��
// lpVBuf:ɫ��V�ź����뻺��
//********************************************************************
int ProcessData(JPEGINFO *pJpgInfo,unsigned char* lpYBuf,unsigned char* lpUBuf,unsigned char* lpVBuf,int width,int height,unsigned char* pOut,int nDataLen)
{

	size_t yBufLen =width*height; //����Y���峤��
	size_t uBufLen=width*height/4; //ɫ��U���峤��
	size_t vBufLen =width*height/4; //ɫ��V���峤��
	float dctYBuf[DCTBLOCKSIZE]; //Y�ź�FDCT������ʱ����
	float dctUBuf[DCTBLOCKSIZE]; //U�ź�FDCT������ʱ����
	float dctVBuf[DCTBLOCKSIZE]; //V�ź�FDCT������ʱ����
	unsigned int mcuNum = 0; //���MCU������
	short yDC = 0; //Y�źŵĵ�ǰ���DC
	short uDC = 0; //U�źŵĵ�ǰ���DC
	short vDC = 0; //V�źŵĵ�ǰ���DC
	unsigned char yCounter = 0; //YUV�źŸ��Ե�д�������
	unsigned char uCounter = 0;
	unsigned char vCounter = 0;
	unsigned int i = 0; //��ʱ����
	unsigned int j = 0;
	unsigned int k = 0;
	unsigned int p = 0;
	unsigned int m = 0;
	unsigned int n = 0;
	unsigned int s = 0;
	mcuNum = (height * width * 3)
		/ (DCTBLOCKSIZE * 3); //����MCU������

	for (p = 0;p < mcuNum; p++) //��������MCU��д��
	{
		yCounter = 1;//MCUIndex[SamplingType][0]; //��������ʽ��ʼ�����źż�����
		uCounter = 1;//MCUIndex[SamplingType][1];
		vCounter = 1;//MCUIndex[SamplingType][2];
	 LOGE(" YUV2Jpg  ProcessData 4");

		for (; i < yBufLen; i += DCTBLOCKSIZE)
		{
			 LOGE(" YUV2Jpg  ProcessData 4.1 %d",i);

			for (j = 0; j < DCTBLOCKSIZE; j++)
			{
			     LOGE(" YUV2Jpg  ProcessData 4.2 %d",j);

				dctYBuf[j] = (float)(lpYBuf[i + j] - 128);
			}
			if (yCounter > 0)
			{
					  LOGE(" YUV2Jpg  ProcessData 4.3 %d",yCounter);

				--yCounter;
				nDataLen = ProcessDU(pJpgInfo,dctYBuf,pJpgInfo->YQT_DCT,pJpgInfo->STD_DC_Y_HT,pJpgInfo->STD_AC_Y_HT,&yDC,pOut,nDataLen);
			}
			else
			{
				break;
			}
		}
		//------------------------------------------------------------------
		for (; m < uBufLen; m += DCTBLOCKSIZE)
		{
			 LOGE(" YUV2Jpg  ProcessData 5");

			for (n = 0; n < DCTBLOCKSIZE; n++)
			{
				dctUBuf[n] = (float)(lpUBuf[m + n] - 128);
			}
			if (uCounter > 0)
			{
				--uCounter;
				nDataLen = ProcessDU(pJpgInfo,dctUBuf,pJpgInfo->UVQT_DCT,pJpgInfo->STD_DC_UV_HT,pJpgInfo->STD_AC_UV_HT,&uDC,pOut,nDataLen);
			}
			else
			{
				break;
			}
		}
		//-------------------------------------------------------------------
		for (; s < vBufLen; s += DCTBLOCKSIZE)
		{
					 LOGE(" YUV2Jpg  ProcessData 6");

			for (k = 0; k < DCTBLOCKSIZE; k++)
			{
				dctVBuf[k] = (float)(lpVBuf[s + k] - 128);
			}
			if (vCounter > 0)
			{
				--vCounter;
				nDataLen = ProcessDU(pJpgInfo,dctVBuf,pJpgInfo->UVQT_DCT,pJpgInfo->STD_DC_UV_HT,pJpgInfo->STD_AC_UV_HT,&vDC,pOut,nDataLen);
			}
			else
			{
				break;
			}
		}
	}
	return nDataLen;
}

int YUV2Jpg(unsigned char* in_Y,unsigned char* in_U,unsigned char* in_V,int width,int height,int quality,int nStride,unsigned char* pOut,unsigned long *pnOutSize)
{

	int nYLen = nStride * height;
	int nUVLen = nYLen >> 2;
	int nDataLen;

	JPEGINFO JpgInfo;
	memset(&JpgInfo,0,sizeof(JPEGINFO));
	JpgInfo.bytenew = 0;
	JpgInfo.bytepos = 7;
	unsigned char* pYBuf = (unsigned char*)malloc(nYLen);
	memcpy(pYBuf,in_Y,nYLen);
	unsigned char* pUBuf = (unsigned char*)malloc(nYLen);
	unsigned char* pVBuf = (unsigned char*)malloc(nYLen);

	ProcessUV(pUBuf,in_U,width,height,nStride);
	ProcessUV(pVBuf,in_V,width,height,nStride);
	// GetDataFromSource(pYBuf,pUBuf,pVBuf,in_Y,in_U,in_V,width);
	DivBuff(pYBuf,width,height,nStride,DCTSIZE,DCTSIZE);
	DivBuff(pUBuf,width,height,nStride,DCTSIZE,DCTSIZE);
	DivBuff(pVBuf,width,height,nStride,DCTSIZE,DCTSIZE);
	quality = QualityScaling(quality);
	SetQuantTable(std_Y_QT,JpgInfo.YQT, quality); // ����Y������
	SetQuantTable(std_UV_QT,JpgInfo.UVQT,quality); // ����UV������

	InitQTForAANDCT(&JpgInfo); // ��ʼ��AA&N��Ҫ��������
	JpgInfo.pVLITAB=JpgInfo.VLI_TAB + 2048; // ����VLI_TAB�ı���
	BuildVLITable(&JpgInfo); // ����VLI��

	nDataLen = 0;
	// д�����
	nDataLen = WriteSOI(pOut,nDataLen);
	nDataLen = WriteAPP0(pOut,nDataLen);
	nDataLen = WriteDQT(&JpgInfo,pOut,nDataLen);
	nDataLen = WriteSOF(pOut,nDataLen,width,height);
	nDataLen = WriteDHT(pOut,nDataLen);
	nDataLen = WriteSOS(pOut,nDataLen);

	// ����Y/UV�źŵĽ�ֱ������huffman������ʹ�ñ�׼��huffman�������Ǽ���ó���ȱ�����ļ��Գ��������ٶȿ�
	BuildSTDHuffTab(STD_DC_Y_NRCODES,STD_DC_Y_VALUES,JpgInfo.STD_DC_Y_HT);
	BuildSTDHuffTab(STD_AC_Y_NRCODES,STD_AC_Y_VALUES,JpgInfo.STD_AC_Y_HT);
	BuildSTDHuffTab(STD_DC_UV_NRCODES,STD_DC_UV_VALUES,JpgInfo.STD_DC_UV_HT);
	BuildSTDHuffTab(STD_AC_UV_NRCODES,STD_AC_UV_VALUES,JpgInfo.STD_AC_UV_HT);

	// ����Ԫ����
	nDataLen = ProcessData(&JpgInfo,pYBuf,pUBuf,pVBuf,width,height,pOut,nDataLen);
	 LOGE(" YUV2Jpg   6.5");
	nDataLen = WriteEOI(pOut,nDataLen);
    LOGE(" YUV2Jpg   7");

	free(pYBuf);
	free(pUBuf);
	free(pVBuf);
	LOGE(" YUV2Jpg   8");
	*pnOutSize = nDataLen;
	return 0;
}

#endif